#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <pthread.h>
#include <shmem.h>
#include "list.h"
#include "cJSON.h"
#include <unix_sock.h>

struct env_info {
    uint8_t head[3];	 //标识位st:
    uint8_t type;		 //数据类型
    uint8_t snum;		 //房间编号
    uint8_t temp[2];	 //温度	
    uint8_t hum[2];		 //湿度
    uint8_t x;			 //三轴信息
    uint8_t y;			 
    uint8_t z;			 
    uint32_t ill;		 //光照
    uint32_t bet;		 //电池电量
    uint32_t adc; 		 //电位器信息
};


#define ENV_LEN sizeof(struct env_info)
#define CONVER_ENV_LEN sizeof(struct conver_env_info)
#define MODULE_UNIX "unixs_m0"

#define LED_ON 0xA1
#define LED_OFF 0xA0
#define BEEP_ON 0x91
#define BEEP_OFF 0x90
#define BEEP_1 0x92
#define BEEP_2 0x93
#define fan_off 0x80
#define fan_on 0x81
#define fan_2 0x82
#define fan_3 0x83

int fan_num = 0;
int led_num = 0;
int beep_num = 0;

static struct unix_param unix_para;
static struct shm_param para;
float temperature;	 //温度	
float humidity;		 //湿度
int ill;		 //光照
float dota_atof (char unitl);
int dota_atoi (const char *cDecade);
float dota_adc (unsigned int ratio);

#define DEV_UART 			"/dev/ttyUSB0"
char success_command[128] = "{\"type\": 2,\"result\": 0,\"msg\":\"控制成功\"}";
char failed_command[128] = "{\"type\": 2,\"result\": 1,\"msg\":\"控制失败\"}";
struct m0_node
{
    int key;
    char name[128];
    int type;
};
struct m0_old
{
    float tem;
    float hum;
    int ill;
    int led;
    int beep;
    int fan;
};
struct m0_old m0_old_info;
struct m0_node_list
{
    struct m0_node node;
    struct list_head list;
};

union val_t
{ 
    int b_val;  //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val;  //浮点值存储空间
};

struct std_node
{
	int key;  //唯一键值
	int type;  //数据点类型
    int dev_type;  //属于哪个设备：m0或modbus
	union val_t old_val;  //变化上报后需要更新旧值
    union val_t new_val;  //从共享内存取出最新数据，放到new_val中
    int ret;  //默认为-1，采集成功后设置为0，采集失败再置-1
};


void serial_init(int fd)
{
    struct termios options;
    tcgetattr(fd, &options);
    options.c_cflag |= ( CLOCAL | CREAD );
    options.c_cflag &= ~CSIZE;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_iflag |= IGNPAR;
    options.c_iflag &= ~(ICRNL | IXON);
    options.c_oflag = 0;
    options.c_lflag = 0;

    cfsetispeed(&options, B115200);
    cfsetospeed(&options, B115200);
    tcsetattr(fd,TCSANOW,&options);
}

//线程1-----采集线程
void *thread_gather(void *arg)
{
    int fd; 
    int ret;
    int i;
    int nbytes = 0;
    struct env_info envinfo;  //原始数据

    fd = open(DEV_UART, O_RDWR);
    if(fd < 0)
    {
        perror ("open uart err\n");
        return ;
    }

    serial_init(fd);
    //循环采集数据
     while (1) {
        nbytes = read(fd, &envinfo, ENV_LEN);
        if(nbytes == ENV_LEN){
            printf("采集成功\n");
        }else {
            printf("err data");
        }

        temperature = envinfo.temp[0] + dota_atof(envinfo.temp[1]);
        humidity = envinfo.hum[0] + dota_atof(envinfo.hum[1]);
        ill = envinfo.ill;

        //开共享内存初始化
        ret = shm_init(&para, "shm_test", sizeof(struct std_node) * 11);
        if (ret < 0)
        {
            return -1;
        }

        struct std_node *m0_data;
        m0_data = shm_getaddr(&para) + (5*sizeof(struct std_node));
        for (i = 0; i < 6; i++)
        {
            m0_data[i].old_val = m0_data[i].new_val;
        }

        printf("conver temperature=%0.2f, humidity=%0.2f, ill=%d\n", \
               temperature, humidity, ill);
        //填充结构体
        m0_data[0].key = 1;
        m0_data[0].dev_type = 0;
        m0_data[0].new_val.f_val = temperature;
        m0_data[0].type = 3; 
        m0_old_info.tem = temperature;

        m0_data[1].key = 2;
        m0_data[1].dev_type = 0;
        m0_data[1].new_val.f_val = humidity;
        m0_data[1].type = 3; 
        m0_old_info.hum = humidity;

        m0_data[2].key = 3;
        m0_data[2].dev_type = 0;
        m0_data[2].new_val.f_val = ill;
        m0_data[2].type = 3; 
        m0_old_info.ill = ill;

        m0_data[3].key = 4;
        m0_data[3].dev_type = 0;
        m0_data[3].new_val.b_val = led_num;
        m0_data[3].type = 1; 
        m0_old_info.led = led_num;

        m0_data[4].key = 5;
        m0_data[4].dev_type = 0;
        m0_data[4].new_val.i_val = beep_num;
        m0_data[4].type = 2;
        m0_old_info.beep = beep_num;

        m0_data[5].key = 6;
        m0_data[5].dev_type = 0;
        m0_data[5].new_val.i_val = fan_num;
        m0_data[5].type = 2; 
        m0_old_info.fan = fan_num;
        
    }

}

//线程2-----控制线程
void *thread_control(void *arg)
{
    int fd;
    char data[256] = {0};
    fd = open(DEV_UART, O_RDWR);
    if(fd < 0)
    {
        perror ("open uart err\n");
        return ;
    }

    serial_init(fd);
    //线程开启UNIX接受上报进程的控制指令
    unix_init_server(&unix_para, MODULE_UNIX);
    printf("测试\n");
    while(1)
    {
        bzero(data, 256);
        if (unix_server_recv(&unix_para, data, 256) > 0)
        {
                printf("测试111\n");
                //解析上报进程发过来的指令
                cJSON *root = NULL;
                int j;
                cJSON *item = NULL;
                cJSON *value_json = NULL;
                cJSON *key_json = NULL;
                root = cJSON_Parse(data);
                if (!root)
                {
                    printf("Error control from thread!\n");
                }
                else
                {
                    //解析上报进程发过来的json
                    item = cJSON_GetObjectItem(root, "data");
                    key_json = cJSON_GetObjectItem(item, "key");
                    value_json = cJSON_GetObjectItem(item, "val");
                    printf("key: %d\n",key_json->valueint);
                    printf("val: %d\n",value_json->valueint);
                    int key = key_json->valueint;
                    switch(key)
                    {
                        case 4:
                        {
                            unsigned char cmd;
                            led_num = value_json->valueint;
                            if(value_json->valueint == 0)
                            {
                                cmd = LED_OFF;
                            }else if(value_json->valueint == 1)
                            {
                                cmd = LED_ON;
                            }
                            write(fd, &cmd, 1);
                            sleep(1);
                            if(m0_old_info.led == value_json->valueint)
                            {
                                unix_server_send(&unix_para, success_command, sizeof(success_command));
                                printf("控制101成功！\n");
                            }else{
                                unix_server_send(&unix_para, failed_command, sizeof(failed_command));
                                printf("控制101失败！\n");
                            }
                            break;
                        }
                        case 5:
                        {
                            beep_num = value_json->valueint;
                            unsigned char cmd;
                            if(value_json->valueint == 0)
                            {
                                cmd = BEEP_OFF;
                            }else if(value_json->valueint == 1)
                            {
                                cmd = BEEP_ON;
                            }else if(value_json->valueint == 2)
                            {
                                cmd = BEEP_1;
                            }else if(value_json->valueint == 3)
                            {
                                cmd = BEEP_2;
                            }
                            write(fd, &cmd, 1);
                            sleep(1);
                            if(m0_old_info.beep == value_json->valueint)
                            {
                                unix_server_send(&unix_para, success_command, sizeof(success_command));
                                printf("控制101成功！\n");
                            }else{
                                unix_server_send(&unix_para, failed_command, sizeof(failed_command));
                                printf("控制101失败！\n");
                            }
                            break;
                        }
                        case 6:
                        {
                            fan_num = value_json->valueint;
                             unsigned char cmd;
                            if(value_json->valueint == 0)
                            {
                                cmd = fan_off;
                            }else if(value_json->valueint == 1)
                            {
                                cmd = fan_on;
                            }else if(value_json->valueint == 2)
                            {
                                cmd = fan_2;
                            }else if(value_json->valueint == 3)
                            {
                                cmd = fan_3;
                            }
                            write(fd, &cmd, 1);
                            sleep(1);
                            if(m0_old_info.fan == value_json->valueint)
                            {
                                unix_server_send(&unix_para, success_command, sizeof(success_command));
                                printf("控制101成功！\n");
                            }else{
                                unix_server_send(&unix_para, failed_command, sizeof(failed_command));
                                printf("控制101失败！\n");
                            }
                            break;
                        }   
                    }
                }
        }
    }
}

int main(int argc, char *argv[])
{

    int fd;
    ssize_t ret1 = 0;
    //打开点表文件
    fd = open("../report/cjson_list.txt",O_RDONLY);
    if(fd < 0)
    {
        perror("fd open err\n");
        return -1;
    }
    char Point_table[2048];

    ret1 = read(fd,Point_table,2048);
    if(ret1 < 0)
    {
        perror("read point table err.");
        return -1;
    }

    //解析点表,创建内核链表
    struct m0_node_list head;
    INIT_LIST_HEAD(&head.list);
    struct m0_node_list m0_node_data_array[5];

    cJSON* root_pt = NULL;
    cJSON* item_pt = NULL;
    cJSON* modbus_pt_bedroom_data = NULL;
    cJSON* modbus_pt_bedroom_data_infomation = NULL;
    cJSON* modbus_pt_bedroom_data_key = NULL;
    cJSON* modbus_pt_bedroom_data_name = NULL;
    cJSON* modbus_pt_bedroom_data_addr = NULL;
    cJSON* modbus_pt_bedroom_data_type = NULL;
    root_pt = cJSON_Parse(Point_table);

    //解析modbus点表
    item_pt = cJSON_GetObjectItem(root_pt,"m0");
    modbus_pt_bedroom_data = cJSON_GetObjectItem(item_pt,"data");
    int array_size = cJSON_GetArraySize(modbus_pt_bedroom_data);
    int k = 0;
    for(k = 0;k<array_size;k++)
    {
        modbus_pt_bedroom_data_infomation = cJSON_GetArrayItem(modbus_pt_bedroom_data,k);
        modbus_pt_bedroom_data_key = cJSON_GetObjectItem(modbus_pt_bedroom_data_infomation,"key");
        modbus_pt_bedroom_data_name = cJSON_GetObjectItem(modbus_pt_bedroom_data_infomation,"name");
        modbus_pt_bedroom_data_type = cJSON_GetObjectItem(modbus_pt_bedroom_data_infomation,"type");
        m0_node_data_array[k].node.key = modbus_pt_bedroom_data_key->valueint;
        m0_node_data_array[k].node.type = modbus_pt_bedroom_data_type->valueint;
        strcpy(m0_node_data_array[k].node.name,modbus_pt_bedroom_data_name->valuestring);
        list_add(&m0_node_data_array[k].list, &head.list);
    }
    struct list_head *pos;
    struct m0_node_list *tmp;
    list_for_each(pos, &head.list)
    {
        tmp = list_entry(pos, struct m0_node_list, list);
        printf("type = %d, key = %d\n",tmp->node.type,tmp->node.key);
    }

    pthread_t tid;
    pthread_t tid2;
    if(pthread_create(&tid,NULL,thread_gather,NULL) != 0)
    {
        perror("pthread create err.");
        return -1;
    }
    if(pthread_create(&tid2,NULL,thread_control,NULL) != 0)
    {
        perror("pthread create err.");
        return -1;
    }

    pthread_join(tid, NULL);
    pthread_join(tid2, NULL);
    return 0;
}

float dota_atof (char unitl)
{
    if (unitl > 100)
    {
        return unitl / 1000.0;
    }
    else if (unitl > 10)
    {
        return unitl / 100.0;
    }
    else
    {
        return unitl / 10.0;
    }
}

int dota_atoi (const char *cDecade)
{
    int result = 0;
    if (' ' != cDecade[0])
    {
        result = (cDecade[0] - 48) * 10;
    }
    result += cDecade[1] - 48;
    return result;
}

float dota_adc (unsigned int ratio)
{
    return ((ratio * 3.3) / 1024);
}